package com.csap.framework.validation.factory;

import com.csap.framework.extension.FilterClassParam;
import com.csap.framework.properties.apidoc.ModelType;
import com.csap.framework.util.CollectionsUtil;
import com.csap.framework.util.exception.ExceptionUtils;
import com.csap.framework.util.map.CsapMap;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import javax.validation.ConstraintValidator;
import javax.validation.constraints.NotNull;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;

/**
 * @author yangchengfu
 * @description 验证实体类
 * @dataTime 2021年-01月-22日 18:01:00
 **/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Validate {
    /**
     * 返回值 过滤参数
     */
    private List<FilterClassParam> filterClassParams = new ArrayList<>();
    /**
     * 字段验证
     * <p>
     * key is fileName ?.fileName
     * value is validate value list
     * <p/>
     * 一级键名称为 controllerName.method.model.field
     * 二级级键名称为 controllerName.method.model.field.field
     * 多级键名称以此类推
     */
    private CsapMap<String, ValidateField> validateField = new CsapMap<>();


    /**
     * 根据字段名称 或者字段验证列表
     *
     * @param fieldKey 字段标识
     * @return 返回字段验证列表
     */
    public ValidateField field(String fieldKey) {
        return validateField.get(fieldKey);
    }

    /**
     * 添加验证的字段
     *
     * @param fieldKey             字段标识
     * @param constraintValidators 验证逻辑
     * @return
     */
    public ValidateField addValidateField(String fieldKey, List<ConstraintValidatorField> constraintValidators) {
        return validateField.computeIfAbsent(fieldKey, k -> new ValidateField().constraintValidators(constraintValidators));
    }

    /**
     * 添加验证的字段
     *
     * @param fieldKey             字段标识
     * @param constraintValidators 验证逻辑
     * @return
     */
    public ValidateField addValidateField(String fieldKey, ValidateField constraintValidators) {
        return validateField.computeIfAbsent(fieldKey, k -> constraintValidators);
    }

    /**
     * 添加验证的字段
     *
     * @param fieldKey 字段标识
     * @return
     */
    public ValidateField addValidateField(String fieldKey) {
        return validateField.computeIfAbsent(fieldKey, k -> new ValidateField());
    }

    /**
     * 添加验证的字段
     *
     * @param fieldKey 字段标识
     * @return
     */
    public ValidateField addValidateField(String fieldKey, BaseModel baseModel) {
        return validateField.computeIfAbsent(fieldKey, k -> new ValidateField().modelType(baseModel.getModelType()));
    }

    /**
     * 过滤返回参数
     *
     * @param modelClass 参数对象
     * @return
     */
    public FilterClassParam filterResponse(Class<?> modelClass) {
        return filterClassParams.stream()
                .filter(i -> modelClass.equals(i.getType()))
                .findFirst()
                .orElseGet(() -> {
                    FilterClassParam filterClassParam = new FilterClassParam();
                    filterClassParam.type(modelClass);
                    filterClassParams.add(filterClassParam);
                    return filterClassParam;
                });
    }

    /**
     * 字段验证
     */
    @Data
    public static class ValidateField {
        /**
         * 验证逻辑
         */
        private List<ConstraintValidatorField> constraintValidators;
        /**
         * 子级验证信息
         */
        private CsapMap<String, ValidateField> children = new CsapMap<>();

        private String key;
        /**
         * 对象类型
         */
        private ModelType modelType;

        public ValidateField modelType(ModelType modelType) {
            this.modelType = modelType;
            return this;
        }

        public ValidateField key(String key) {
            this.key = key;
            return this;
        }

        public ValidateField constraintValidators(List<ConstraintValidatorField> constraintValidators) {
            this.constraintValidators = constraintValidators;
            return this;
        }

        /**
         * 添加验证的字段
         *
         * @param fieldKey             字段标识
         * @param constraintValidators 验证逻辑
         * @return
         */
        public ValidateField addValidateField(String fieldKey, List<ConstraintValidatorField> constraintValidators, BaseModel baseModel) {
            return children.computeIfAbsent(fieldKey, k -> new ValidateField().modelType(baseModel.getModelType()).constraintValidators(constraintValidators));
        }

        /**
         * 添加验证的字段
         *
         * @param fieldKey      字段标识
         * @param validateField 验证参数
         * @return
         */
        public ValidateField addValidateField(String fieldKey, ValidateField validateField) {
            return children.computeIfAbsent(fieldKey, k -> validateField);
        }

        /**
         * 验证当前字段
         *
         * @param value 需要验证的数据
         * @return
         */
        public ValidateField validators(Object value) {
            return validators(value, constraintValidators);
        }

        /**
         * 验证当前字段
         *
         * @param value                   需要验证的数据
         * @param constraintValidatorList 需要验证的业务逻辑
         * @return
         */
        public ValidateField validators(Object value, List<ConstraintValidatorField> constraintValidatorList) {
            if (CollectionsUtil.isNotEmpty(constraintValidatorList)) {
                constraintValidatorList.stream().filter(i -> !i.getValidator().isValid(value, null)).findFirst().ifPresent(i -> {
                    throw ExceptionUtils.mpe((Object) i.getCode(), i.getMessage());
                });
            }
            return this;
        }

        /**
         * 验证当前级联业务
         */
        public ValidateField validatorsChildren(Function<String, Object> function) {
            children.entrySet().stream().map(e -> {
                Object o = function.apply(e.getKey());
                return e;
            });
            return null;
        }

    }

    /**
     * 字段验证详细信息
     */
    @Data
    @AllArgsConstructor
    @NotNull
    @Builder
    public static class ConstraintValidatorField {
        /**
         * 验证逻辑
         */
        private ConstraintValidator validator;
        /**
         * 当前注解
         */
        private Annotation annotation;
        /**
         * 编码
         */
        private String code;
        /**
         * 提示消息
         */
        private String message;
    }
}
